package com.atguigu.utils;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

public class PerformanceTest {

    //定义测试方法
    public static <T> PerformanceRunnerResult performanceTest(int requests, int concurrent, Runnable runnable) {

        System.out.println("测试方法开始");

        //封装返回值对象
        PerformanceRunnerResult result = new PerformanceRunnerResult();

        //线程池
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                concurrent,
                concurrent,
                0L,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>()
        );

        //启动所有核心线程
        threadPoolExecutor.prestartAllCoreThreads();

        //创建countDownLatch
        CountDownLatch countDownLatch = new CountDownLatch(requests);

        //成功请求数，最快请求数，最慢请求数；
        AtomicInteger success = new AtomicInteger();
        AtomicInteger fast = new AtomicInteger(Integer.MAX_VALUE);
        AtomicInteger slow = new AtomicInteger(Integer.MIN_VALUE);

        //开始时间
        long start = System.currentTimeMillis();

        try {
            for (int i = 0; i < requests; i++) {
                threadPoolExecutor.execute(() -> {
                    try {
                        //单个业务开始时间
                        long simpleStart = System.currentTimeMillis();
                        //被测试的单个业务
                        runnable.run();
                        //单个业务的结束时间
                        long simpleEnd = System.currentTimeMillis();
                        //单个业务的执行耗时
                        long costTime = simpleEnd - simpleStart;
                        //最快业务耗时
                        setFastTime(fast, costTime);
                        //最慢业务耗时
                        setSlowTime(slow, costTime);
                        //请求成功数量
                        success.incrementAndGet();
                    } catch (Exception e) {
                        System.out.println(e.getMessage());
                    } finally {
                        countDownLatch.countDown();
                    }
                });
            }
            //阻塞当前线程，等到压测结束后，该方法会被唤醒，线程继续向下走
            countDownLatch.await();
        } catch (Exception e) {
            System.out.println(e.getMessage());
        } finally {
            threadPoolExecutor.shutdown();
        }
        //结束时间
        long end = System.currentTimeMillis();
        System.out.println("----costTime: " + (end - start) + " 毫秒");

        //组装最后的结果并返回
        result.setRequests(requests);
        result.setConcurrency(concurrent);
        result.setSuccessRequests(success.get());
        result.setFailRequests(requests - result.getSuccessRequests());
        result.setTimeTakenForTests((int) (end - start));
        result.setRequestsPerSecond((float) requests * 1000f / (float) (result.getTimeTakenForTests()));
        result.setTimePerRequest((float) result.getTimeTakenForTests() / (float) requests);
        result.setFastestCostTime(fast.get());
        result.setSlowestCostTime(slow.get());
        return result;
    }

    private static void setSlowTime(AtomicInteger slow, long costTime) {
        while (true) {
            if (slow.get() < (int) costTime) {
                slow.compareAndSet(slow.get(), (int) costTime);
            } else {
                break;
            }
        }
    }

    private static void setFastTime(AtomicInteger fast, long costTime) {
        while (true){
            if (fast.get() > (int) costTime){
                fast.compareAndSet(fast.get(),(int) costTime);
            }else {
                break;
            }
        }
    }
}
